/** 
Copyright (c) 2010, Sheikh Abdul Wahid Ahmed
Details @ http://extremecodeworld.codeplex.com/license
**/

using System;
using System.Xml;
using System.IO;
using System.Text;
using System.Xml.Xsl;
using EXtremecode.EntityDefinition;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace EXtremecode.EntityDefinitionGenerator
{
	/// <summary>
	/// Summary description for BusinessObjectGenerator.
	/// </summary>
	delegate void GeneratorHandler(string message);
	internal class BusinessObjectGenerator
	{
		private const string CUSTOM_CODE_REGION_START="#region Custom Code";
		private const string CUSTOM_CODE_REGION_END="#endregion Custom Code";
		public static event GeneratorHandler ClassGenerate;
		internal BusinessObjectGenerator()
		{
			//
			// TODO: Add constructor logic here
			//
		}
		internal static void GenerateCode(XmlDocument docSource,string strStyleSheetPath,string strNamespace,DirectoryInfo  dirOutput)
		{
	
			try
			{
				XslTransform xsltr=new XslTransform();
				xsltr.Load(strStyleSheetPath);
				XmlNamespaceManager manager=new XmlNamespaceManager(docSource.NameTable);
				manager.AddNamespace("xyz",XMLSpecific.XMLN);
				XmlNodeList nodes;
				nodes=docSource.DocumentElement.SelectNodes("xyz:entity[@name]",manager);
			

				foreach(XmlNode node in nodes)
				{
					FileStream  fileStream=null;
					MemoryStream  tempStorage=new MemoryStream();
					string strClassName=node.Attributes["className"].Value;
					try
					{
						StringBuilder sbCustomCodeForObject=new StringBuilder(),sbCustomCodeForCollection=new StringBuilder();
						fileStream=GetFileStream(strClassName,dirOutput,false);
					
						//Store Data Temparory,in case of failure,data will be copied to stream from tempStorage
						CopyData(fileStream,tempStorage);					
						PopulateStringBuildersWithCustomCode(sbCustomCodeForObject,sbCustomCodeForCollection,fileStream);
						fileStream.Close();
						fileStream=GetFileStream(strClassName,dirOutput,true);
						StreamWriter writer=new StreamWriter(fileStream); 
					
						XsltArgumentList argus=new XsltArgumentList();
						argus.AddParam("space",""," "); 
						argus.AddParam("namespace","",strNamespace); 
						argus.AddParam("customCode_object","",sbCustomCodeForObject.ToString().Trim()); 
						argus.AddParam("customCode_coll","",sbCustomCodeForCollection.ToString().Trim()); 
					
						XmlDocument tempDoc=new XmlDocument();
						tempDoc.LoadXml(node.OuterXml);
				
						xsltr.Transform(tempDoc,argus, writer, null);
						if(ClassGenerate != null)ClassGenerate(string.Format("{0} \ngenerated..",strClassName));

					}
					catch(Exception)
					{
						if(fileStream != null)fileStream.Close();
						fileStream=GetFileStream(strClassName,dirOutput,true);
						CopyData(tempStorage,fileStream);					
					}
					finally
					{
						if(fileStream != null)fileStream.Close();
					}
				
				
				}
			}
			catch(Exception ex)
			{
				throw Logging.Logger.Write(ex);
			}
			finally
			{
				Logging.Logger.Write();
			}
		}
		
		internal static void GenerateXtraCode(XmlDocument docSource,string strStyleSheetPath,string strNamespace,string strProviderPath,string strClassName,string strProviderNamspace)
		{
			try
			{
				FileStream  fileStream=null;
				try
				{
					XslTransform xsltr=new XslTransform();
					xsltr.Load(strStyleSheetPath);
					fileStream=File.Open(strProviderPath,FileMode.Create);
					StreamWriter writer=new StreamWriter(fileStream); 
					XsltArgumentList argus=new XsltArgumentList();
					argus.AddParam("space",""," "); 
					argus.AddParam("namespace","",strNamespace); 
					argus.AddParam("providerNamespace","",strProviderNamspace); 
					argus.AddParam("nameOfClass","",strClassName); 
					xsltr.Transform(docSource,argus, writer, null);

				}
				catch(Exception ex)
				{
					Console.WriteLine(ex.Message );
				}
				finally
				{
					if(fileStream != null)fileStream.Close();
				}
			}
			catch(Exception ex)
			{
				throw Logging.Logger.Write(ex);
			}
			finally
			{
				Logging.Logger.Write();
			}
		}

		private static void CopyData(Stream sourceStream,Stream destinationStream)
		{
			try
			{
				sourceStream.Position=0;
				destinationStream.Position=0;

				StreamReader rdr=new StreamReader(sourceStream);
				StreamWriter writer=new StreamWriter(destinationStream);
				writer.AutoFlush=true;
				string line;
				while ((line = rdr.ReadLine()) != null) 
				{
					writer.WriteLine(line);
				}
			}
			catch(Exception ex)
			{
				throw Logging.Logger.Write(ex);
			}
			finally
			{
				//Logging.Logger.Write();
			}

		}
		private static FileStream GetFileStream(string strClassName,DirectoryInfo dir,bool overwrite)
		{
			try
			{
				FileStream fileStream;
				string strFileName=string.Format("{0}.cs",strClassName);
				FileInfo[] files = dir.GetFiles(strFileName);
				if(files.Length>0)
				{
					if(overwrite)
						fileStream= files[0].Open(FileMode.Create,FileAccess.ReadWrite,FileShare.Read);
					else
						fileStream= files[0].Open(FileMode.Open,FileAccess.ReadWrite,FileShare.Read);

				}
				else
				{
					FileInfo file=new FileInfo(string.Format(@"{0}\{1}",dir.FullName,strFileName));
					fileStream=file.Open(FileMode.Create,FileAccess.ReadWrite);
				}
			
				return fileStream;
			}
			catch(Exception ex)
			{
				throw Logging.Logger.Write(ex);
			}
			finally
			{
				//Logging.Logger.Write();
			}
		}
		private static void PopulateStringBuildersWithCustomCode(StringBuilder sbCustomCodeForObject,StringBuilder sbCustomCodeForCollection,Stream fileStream)
		{
			try
			{
				fileStream.Position=0;
				StreamReader streamReader=new StreamReader(fileStream);
				string line="";
				string strSearchFor=CUSTOM_CODE_REGION_START;
				StringBuilder[] sbs=new StringBuilder[]{sbCustomCodeForObject,sbCustomCodeForCollection}; 
				int index=0;
				bool bStartStoring=false;
				string nextLine="";
				while ((line = streamReader.ReadLine()) != null) 
				{
					if(line.IndexOf(strSearchFor)>=0) 
					{
						bStartStoring = !bStartStoring;
						if(!bStartStoring)
						{
							index++;
							strSearchFor=CUSTOM_CODE_REGION_START;
						}
						else
						{
							strSearchFor=CUSTOM_CODE_REGION_END;
							continue;
						}
					}
					if(bStartStoring)
					{
						sbs[index].Append(nextLine + line);
						nextLine = "\n";
					}
				}
			}
			catch(Exception ex)
			{
				throw Logging.Logger.Write(ex);
			}
			finally
			{
				//Logging.Logger.Write();
			}

		
			
		}
		
	}
}
